package com.sencorsta.ids.core.application.proxy;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.sencorsta.ids.core.application.master.MasterClient;
import com.sencorsta.ids.core.configure.SysConfig;
import com.sencorsta.ids.core.configure.TypeProtocol;
import com.sencorsta.ids.core.configure.TypeSerialize;
import com.sencorsta.ids.core.entity.Server;
import com.sencorsta.ids.core.function.FunctionSystem;
import com.sencorsta.ids.core.function.SynFunction;
import com.sencorsta.ids.core.log.Out;
import com.sencorsta.ids.core.tcp.socket.client.RpcClientBootstrap;
import com.sencorsta.ids.core.tcp.socket.coder.RpcCodecFactory;
import com.sencorsta.ids.core.tcp.socket.protocol.RpcMessage;
import io.netty.channel.Channel;

import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ProxyClient {
    // 服务器列表
    public static final ConcurrentHashMap<String, ConcurrentHashMap<String, Server>> totalServers = new ConcurrentHashMap<String, ConcurrentHashMap<String, Server>>();

    static RpcClientBootstrap bootstrap = new RpcClientBootstrap("Proxy",new ProxyCodecFactory(new ProxySessionHandler()));

//    private static ExecutorService __EXECUTOR__ = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2 + 1);

//    private static void sendMsg(RpcMessage message){
//        __EXECUTOR__.execute(()->{
//            message.channel.writeAndFlush(message);
//        });
//    };

    // 维护链接
    public static synchronized void maintenanceList(JSONObject json) {
        // 已经有的服务器增加标识
        for (var map : totalServers.values()) {
            for (Server server : map.values()) {
                server.clearflag = true;
            }
        }

        Out.trace("************************当前已经连接Master的服务器************************");
        for (var keys : json.keySet()) {
            Out.trace("-------------------------------------------------------------");
            Out.trace(keys + ":");
            JSONArray array = json.getJSONArray(keys);
            for (Object obj : array) {
                Server serverTemp = JSON.toJavaObject((JSONObject) obj, Server.class);
                ProxyClient.connect(serverTemp);
            }
            Out.trace("-------------------------------------------------------------");
        }
        Out.trace("**************************************************************************");

        // 清理不存在的服务器
        for (var map : totalServers.values()) {
            for (Server server : map.values()) {
                if (server.clearflag == true) {
                    ProxyClient.disconnect(server);
                }
            }
        }

        MasterClient.getInstance().isAlert = true;

        //打印当前所有激活服务器
        StringBuffer sb = new StringBuffer();
        sb.append("打印当前所有激活服务器:");
        sb.append("\n");
        for (var map : totalServers.values()) {
            for (Server server : map.values()) {
                if (server != null) {
                    Channel channelTemp = server.channel();
                    if (channelTemp != null && channelTemp.isActive()) {
                        sb.append(server.sid);
                        sb.append("\n");
                    }
                }
            }
        }
        Out.trace(sb);


    }

    public static void connect(Server server) {
//        if (bootstrap == null) {
//            bootstrap = new RpcClientBootstrap(new RpcCodecFactory(new ProxySessionHandler()));
//        }

        ConcurrentHashMap<String, Server> serverList = totalServers.get(server.type);
        if (serverList == null) {
            serverList = new ConcurrentHashMap<>();
            totalServers.put(server.type, serverList);
        }
        Server serverTemp = serverList.get(server.sid);
        boolean needBind = false;
        if (serverTemp != null) {
            Channel channelTemp = serverTemp.channel();
            if (channelTemp != null && channelTemp.isActive()) {
                Out.debug("已存在的服务,且通信不为空,跳过处理:", server.sid);
            } else {
                needBind = true;
                Out.debug("已存在的服务,但channel为空,重新绑定:", server.sid);
            }
        } else {
            serverTemp = server;
            needBind = true;
            serverList.put(serverTemp.sid, serverTemp);
            Out.debug("新的服务,绑定:", server.sid);
        }

        if (needBind) {
            Channel channel = null;
            int count = 1, wait = 3000;
            while (channel == null) {
                //先连接外网IP
                channel = bootstrap.connect(server.backPublicHost, server.backPort);
                if (channel == null) {
                    //尝试连接本地ip
                    Out.debug("外网ip绑定失败，尝试连接本地ip...");
                    channel = bootstrap.connect(server.backHost, server.backPort);
                    Out.debug("绑定本地IP成功:", server.backPublicHost);
                } else {
                    Out.debug("绑定外网IP成功:", server.backPublicHost);
                }
                if (channel == null) {
                    FunctionSystem.waitMills(wait * count);
                    Out.warn(" reconnect ", server.toString());
                    if (count++ == 3) {
                        Out.warn("reconnec over times quit!!!");
                        return;
                    }
                }
            }
            serverTemp.bind(channel);
        }

        serverTemp.clearflag = false;
        Out.trace(serverTemp);
    }

    public static boolean hasConnect(String type) {
        if (ProxyClient.totalServers.containsKey(type)) {
            ConcurrentHashMap<String, Server> serverList = totalServers.get(type);
            if (serverList == null) {
                return false;
            }
            for (Server serverTemp : serverList.values()
            ) {
                if (serverTemp != null) {
                    Channel channelTemp = serverTemp.channel();
                    if (channelTemp != null && channelTemp.isActive()) {
                        return true;
                    }
                }
            }
        }
        return false;
    }


    public static void sendByType(RpcMessage message, String type) {
        ConcurrentHashMap<String, Server> serverMapTemp = totalServers.get(type);
        if (serverMapTemp != null && serverMapTemp.size() > 0) {
            Out.debug("sendByType开始:", type);
            Server bestServer = getBestServerByType(type);
            if (bestServer != null) {
                bestServer.channel().writeAndFlush(message);
                //message.channel=bestServer.channel();
                //sendMsg(message);
            }
        } else {
            Out.warn("sendByType:类型不存在:", type);
        }
    }


    public static void sendBySID(RpcMessage message, String type, String SID) {
        ConcurrentHashMap<String, Server> serverMapTemp = totalServers.get(type);
        if (serverMapTemp != null && serverMapTemp.size() > 0) {
            Out.debug("sendBySID开始:", type);
            if (serverMapTemp.containsKey(SID)) {
                Server bestServer = serverMapTemp.get(SID);
                if (bestServer != null) {
                    bestServer.channel().writeAndFlush(message);
                    //message.channel=bestServer.channel();
                    //sendMsg(message);
                    return;
                }
            }
            Out.warn("sendBySID:失败 没有找到对应服务器:", SID);
        } else {
            Out.warn("sendBySID:类型不存在:", type);
        }
    }

    public static void broadcast(RpcMessage message, String type, String subscribeId) {
        ConcurrentHashMap<String, Server> serverMapTemp = totalServers.get(type);
        if (serverMapTemp != null && serverMapTemp.size() > 0) {
            Out.debug("broadcast开始:", type);

            JSONObject obj = new JSONObject();
            obj.put("subscribeId", SysConfig.getInstance().get("server.type") +"."+subscribeId);
            obj.put("method", message.method);
            obj.put("serializeType", message.serializeType);
            obj.put("data", message.data);


            for (Server server : serverMapTemp.values()) {
                RpcMessage broadcast = new RpcMessage(TypeProtocol.TYPE_RPC_REQ);
                broadcast.method = "Broadcast";
                broadcast.data = obj.toJSONString().getBytes();
                broadcast.serializeType = TypeSerialize.TYPE_JSON;
                server.channel().writeAndFlush(broadcast);
//                message.channel=server.channel();
//                sendMsg(message);
            }
        } else {
            Out.warn("broadcast:类型不存在:", type);
        }
    }

    public static void subscribe(String desType,String srcType,String subscribeId, String userId) {
        ConcurrentHashMap<String, Server> serverMapTemp = totalServers.get(desType);
        if (serverMapTemp != null && serverMapTemp.size() > 0) {
            Out.debug("subscribe开始:", desType);

            JSONObject obj = new JSONObject();
            obj.put("subscribeId", subscribeId);
            obj.put("userId", userId);
            obj.put("type", srcType);

            for (Server server : serverMapTemp.values()) {
                RpcMessage message = new RpcMessage(TypeProtocol.TYPE_RPC_REQ);
                message.method = "Subscribe";
                message.data = obj.toJSONString().getBytes();
                message.serializeType = TypeSerialize.TYPE_JSON;
                server.channel().writeAndFlush(message);
//                message.channel=server.channel();
//                sendMsg(message);
            }
        } else {
            Out.warn("subscribe:类型不存在:", desType);
        }
    }

    public static void unSubscribe(String desType,String srcType,String subscribeId, String userId) {
        ConcurrentHashMap<String, Server> serverMapTemp = totalServers.get(desType);
        if (serverMapTemp != null && serverMapTemp.size() > 0) {
            Out.debug("UnSubscribe开始:", desType);

            JSONObject obj = new JSONObject();
            obj.put("subscribeId", subscribeId);
            obj.put("userId", userId);
            obj.put("type", srcType);

            for (Server server : serverMapTemp.values()) {
                RpcMessage message = new RpcMessage(TypeProtocol.TYPE_RPC_REQ);
                message.method = "UnSubscribe";
                message.data = obj.toJSONString().getBytes();
                message.serializeType = TypeSerialize.TYPE_JSON;
                server.channel().writeAndFlush(message);
//                message.channel=server.channel();
//                sendMsg(message);
            }
        } else {
            Out.warn("UnSubscribe:类型不存在:", desType);
        }
    }

    public static void userLeave(String userId, Set<String> types) {
        Out.debug("userLeave开始:", userId);
        JSONObject obj = new JSONObject();
        obj.put("userId", userId);
        for (String type : types) {
            ConcurrentHashMap<String, Server> serverMapTemp = totalServers.get(type);
            if (serverMapTemp != null && serverMapTemp.size() > 0) {
                Out.debug("userLeave开始:", userId);
                for (Server server : serverMapTemp.values()) {
                    RpcMessage broadcast = new RpcMessage(TypeProtocol.TYPE_RPC_REQ);
                    broadcast.method = "UserLeave";
                    broadcast.data = obj.toJSONString().getBytes();
                    broadcast.serializeType = TypeSerialize.TYPE_JSON;
                    server.channel().writeAndFlush(broadcast);
                }
            } else {
                Out.warn("userLeave:类型不存在:", type);
            }
        }
    }

    public static void disconnect(Server server) {
        ConcurrentHashMap<String, Server> serverList = totalServers.get(server.type);
        if (serverList.containsKey(server.sid)) {
            serverList.remove(server.sid);
            Out.debug("清理服务:", server.sid);
        }
    }

    public static Server getBestServerByType(String type) {
        ConcurrentHashMap<String, Server> serverList = totalServers.get(type);
        if (serverList == null) {
            return null;
        }
        Server bestServer = null;
        int bestFreeMemory = 0;
        for (String keyTemp : serverList.keySet()) {
            Server tempServer = serverList.get(keyTemp);
            int freeMemory = tempServer.freeMemory;
            if (freeMemory >= bestFreeMemory) {
                bestServer = tempServer;
            }
        }
        return bestServer;
    }


    public static RpcMessage requestByType(RpcMessage req, String type) {
        ConcurrentHashMap<String, Server> serverMapTemp = totalServers.get(type);
        if (serverMapTemp != null && serverMapTemp.size() > 0) {
            Out.debug("requestByType开始:", type);
            Server bestServer = getBestServerByType(type);
            if (bestServer != null) {
                req.channel = bestServer.channel();
                return SynFunction.request(req);
            } else {
                Out.warn("requestByType:服务器不存在:", type);
            }
        } else {
            Out.warn("requestByType:类型不存在:", type);
        }
        return null;

    }


}
